<?php


namespace Plugin\PaypalSiteB\Controllers;

use Beike\Models\Order;
use Beike\Repositories\OrderPaymentRepo;
use Beike\Repositories\OrderRepo;
use Beike\Repositories\SettingRepo;
use Beike\Services\StateMachineService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Plugin\PaypalSiteB\Models\PayProductName;
use Plugin\PaypalSiteB\Models\PollingPaymentOrders;
use Plugin\PaypalSiteB\Services\PollingPaypalTools;
use Srmklive\PayPal\Services\PayPal;

class PollingPaypalController
{
    private PayPal $paypalClient;

    private function initPaypal($orderNo)
    {
        $payment_code       = 'paypal_site_b';
        $pollingPaypalTools = new PollingPaypalTools();
        $settings           = $pollingPaypalTools->getPollingSetting($orderNo, $payment_code);
        if (empty($settings)) {
            die("请先配置支付帐户");
        }

        $order = Order::query()->where('number', $orderNo)->first();

        $config = [
            'mode'           => $settings['is_debug'] == 1 ? 'sandbox' : 'live',
            'sandbox'        => [
                'client_id'     => $settings['key'],
                'client_secret' => $settings['secret'],
            ],
            'live'           => [
                'client_id'     => $settings['key'],
                'client_secret' => $settings['secret'],
            ],
            'payment_action' => 'Sale',
            'currency'       => $order->currency_code,
            'notify_url'     => '',
            'locale'         => 'en_US',
            'validate_ssl'   => false,
        ];
        config(['paypal' => null]);


        $this->paypalClient = new PayPal($config);
        $index              = 0;
        while ($index < 3) {
            $index++;
            try {
                $token = $this->paypalClient->getAccessToken();
                break;
            } catch (\ErrorException $exception) {
                $token = null;
            }
        }
        if (empty($token)) {//帐户有问题了，直接关闭该帐户
            $allSettings = plugin_setting($payment_code . '.setting', []);
            if (!empty($allSettings)) {
                $allSettings2 = $allSettings['polling_paypal'];
                foreach ($allSettings2 as $key => $setting) {
                    if ($setting['key'] == $settings['key']) {
                        $allSettings2[$key]['status'] = 0;
                    }
                }
                $allSettings['polling_paypal'] = $allSettings2;

                SettingRepo::storeValue('setting', $allSettings, $payment_code, 'plugin');
            }

            die('bad account');
        } else {
            $this->paypalClient->setAccessToken($token);
        }
    }


    /**
     * 创建 paypal 订单
     * @param Request $request
     * @return JsonResponse
     * @throws \Throwable
     */
    public function create(Request $request)
    {
        $data        = \json_decode($request->getContent(), true);
        $orderNumber = $data['orderNumber'];
        $this->initPaypal($orderNumber);

        $customer = current_customer();
        $order    = OrderRepo::getOrderByNumber($orderNumber, $customer);
        $total    = round($order->total, 2);

        $paypalOrder = $this->paypalClient->createOrder([
            'intent'         => 'CAPTURE',
            'purchase_units' => [
                [
                    'amount'      => [
                        'currency_code' => $order->currency_code,
                        'value'         => $total,
                    ],
                    'description' => $this->getOrderDesc(128, $order),
                ],
            ],
        ]);
        if (isset($paypalOrder['id'])) {
            Log::debug($paypalOrder['id']);
            $payment_code = "paypal_site_b";
            PollingPaymentOrders::query()->where("order_no", $orderNumber)->where("payment_code", $payment_code)->update([
                'gateway_order_id' => $paypalOrder['id']
            ]);

        }
        return response()->json($paypalOrder);
    }

    public function getOrderDesc($length, $order)
    {
        $productIds = [];
        foreach ($order->orderProducts as $product) {
            $productIds[] = $product->product_id;
        }

        $productNames = PayProductName::query()->whereIn('product_id', $productIds)->get();

        $tmpProductNames = [];
        foreach ($productNames as $productName) {
            $tmpProductNames[$productName->product_id] = $productName->product_name;
        }

        $productsName = '';
        foreach ($order->orderProducts as $product) {
            $newProductsName = $productsName;
            if ($newProductsName) {
                $newProductsName .= '; ';
            }
            $newProductsName .= isset($tmpProductNames[$product->product_id]) ? $tmpProductNames[$product->product_id] : $product->name;
            if (strlen($newProductsName) > $length) {
                return $productsName;
            }
            $productsName = $newProductsName;
        }

        return $productsName;
    }

    /**
     * 客户同意后扣款回调
     * @param Request $request
     * @return JsonResponse
     * @throws \Throwable
     */
    public function capture(Request $request): JsonResponse
    {
        $data = \json_decode($request->getContent(), true);
        Log::debug($data);
        $orderNumber = $data['orderNumber'];
        $this->initPaypal($orderNumber);

        $customer = current_customer();
        $order    = OrderRepo::getOrderByNumber($orderNumber, $customer);

        $paypalOrderId = $data['paypalOrderId'];
        OrderPaymentRepo::createOrUpdatePayment($order->id, ['request' => $data]);
        $result        = $this->paypalClient->capturePaymentOrder($paypalOrderId);
        OrderPaymentRepo::createOrUpdatePayment($order->id, ['response' => $result]);
        try {
            DB::beginTransaction();
            if ($result['status'] === 'COMPLETED') {
                StateMachineService::getInstance($order)->changeStatus(StateMachineService::PAID);
                DB::commit();
            }
        } catch (\Exception $e) {
            DB::rollBack();
            dd($e);
        }

        return response()->json($result);
    }
}
